package com.wenjiang.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.wenjiang.common.constat.RedisKey;
import com.wenjiang.common.dto.OrderParam;
import com.wenjiang.common.dto.SecKillGoodParams;
import com.wenjiang.common.exception.SystemException;
import com.wenjiang.common.lang.Result;
import com.wenjiang.entity.MallGood;
import com.wenjiang.entity.MallOrder;
import com.wenjiang.entity.MallSecKillGood;
import com.wenjiang.mapper.MallGoodMapper;
import com.wenjiang.mapper.MallOrderMapper;
import com.wenjiang.mapper.MallSecKillGoodMapper;
import com.wenjiang.service.MallGoodService;
import com.wenjiang.service.MallOrderService;
import com.wenjiang.service.MallSecKillGoodService;
import com.wenjiang.service.QuarzService;
import com.wenjiang.task.SecKillEndJob;
import com.wenjiang.util.RedisUtils;
import org.quartz.JobDataMap;
import org.quartz.Scheduler;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

@Service
@Transactional
public class MallSecKillGoodServiceImpl extends ServiceImpl<MallSecKillGoodMapper, MallSecKillGood> implements MallSecKillGoodService {


    private static final String secKillEndGroup = "secKillEndGroup";


    @Autowired
    MallGoodService mallGoodService;
    @Autowired
    MallOrderMapper mallOrderMapper;
    @Autowired
    RabbitTemplate rabbitTemplate;

    @Autowired
    RedisUtils redisUtils;

    @Autowired
    MallOrderService mallOrderService;

    // 当前操作的客户端
    @Autowired
    RedissonClient redissonClient;

    @Autowired
    Scheduler scheduler;

    @Autowired
    SecKillEndJob secKillEndJob;

    @Autowired
    QuarzService quarzService;

    @Autowired
    MallGoodMapper mallGoodMapper;

    /**
     * 获取秒杀商品信息
     * @return
     */
    @Override
    public Result getSecKillGood() {


        // 获取缓存信息
        Object value = redisUtils.get(RedisKey.mallSecKillGoodKey);
        if (value==null){
            // 查询秒杀的商品
            QueryWrapper <MallGood> SecKillGoodQuery= new QueryWrapper<>();
            SecKillGoodQuery.eq("good_status", 2);
            List<MallGood> secKillGoods= mallGoodMapper.selectList(SecKillGoodQuery);
            value=secKillGoods;
            redisUtils.set(RedisKey.mallSecKillGoodKey, value,600);
        }

        //直接返回数组
        return Result.succ(value);
    }

    /**
     * 开启一个秒杀
     *
     * @param mallSecKillGood
     * @return
     */
    @Override
    public Result addSecKill(MallSecKillGood mallSecKillGood) {


        //根据商品id查询库存
        MallGood good = mallGoodService.getById(mallSecKillGood.getGoodId());


        //判断商品 是否下架了  或者商品库存够不够
        if (good.getGoodStatus() == 0) {
            return Result.fail("该商品已下架，无法开启秒杀");
        }

        //
        if (good.getGoodCount() <= mallSecKillGood.getStock()) {
            return Result.fail("商品库存不足，无法开启秒杀");
        }

        //判断商品是否正在开启秒杀
        QueryWrapper<MallSecKillGood> mallSecKillGoodQueryWrapper = new QueryWrapper<>();
        mallSecKillGoodQueryWrapper.eq("is_end", 0);
        mallSecKillGoodQueryWrapper.eq("good_id", mallSecKillGood.getGoodId());

        MallSecKillGood secKillGood = getOne(mallSecKillGoodQueryWrapper);
        if (secKillGood != null) {
            return Result.fail("该商品已存在秒杀,无法开启");
        }


        //插入数据库
        save(mallSecKillGood);

        //修改商品状态
        UpdateWrapper<MallGood> mallGoodUpdateWrapper = new UpdateWrapper<>();
        mallGoodUpdateWrapper.set("good_status", 2);
        mallGoodUpdateWrapper.eq("good_id", mallSecKillGood.getGoodId());
        mallGoodService.update(mallGoodUpdateWrapper);


        //创建秒杀结束后的定时任务
        String jobName = mallSecKillGood.getStartTime() + mallSecKillGood.getGoodId().toString();
        secKillEndJob.setJobName(jobName);
        secKillEndJob.setJobGroup(secKillEndGroup);

        //创建定时任务的数据
        JobDataMap jobDataMap = new JobDataMap();
        jobDataMap.put("goodId", mallSecKillGood.getGoodId());

        secKillEndJob.setJobDataMap(jobDataMap);
        secKillEndJob.setStartTime(DateUtil.formatLocalDateTime(mallSecKillGood.getEndTime()));
        secKillEndJob.setClassName("com.wenjiang.task.SecKillEndJob");
        //添加定时任务
        quarzService.addJob(secKillEndJob);



        //创建一个hashSet 用于存抢购该商品的用户
        redisUtils.sSet(RedisKey.mallSecKillUser + good.getGoodId(), 0);

        //修改redis对应的商品库存
        redisUtils.set(RedisKey.mallGoodCount + mallSecKillGood.getGoodId(), mallSecKillGood.getStock());

        return Result.succ("开启秒杀成功");
    }


    /**
     * 获取秒杀商品信息
     */




    /**
     * 抢购一个商品
     */

    @Override
    public Result SecKillGood(SecKillGoodParams secKillGoodParams) {


        //判断秒杀是否开始了

        //判断是否已经结束了

        // 判断是否已经卖完了;

        // 判断是否重复购买
        Set<Object> objects = redisUtils.sGet(RedisKey.mallSecKillUser+secKillGoodParams.getGoodId().toString());
        if (objects.contains(secKillGoodParams.getUserId())){
            return Result.fail("该用户已经抢购买过商品，限购一次!");
        }

        //判断商品是否已经卖完了 一重检测 避免直接加锁
        Integer count1= (Integer) redisUtils.get((RedisKey.mallGoodCount+secKillGoodParams.getGoodId()));
        if (count1<0){
            return Result.fail("商品抢购完了！");
        }




        //获取分布式锁 (对象锁)
        RLock lock = redissonClient.getLock(RedisKey.lock+"order");
        //进行加锁
        try {
            boolean tryLock = lock.tryLock(5, TimeUnit.SECONDS);
            if (tryLock==false){
                System.out.println("请稍后重试！系统繁忙");
            }
        }catch (Exception e){
            throw  new SystemException();
        }


        try {
            Integer count = (Integer) redisUtils.get(RedisKey.mallGoodCount + secKillGoodParams.getGoodId());
            //判断库存 获取库存
            if (count <= 0) {
                return Result.fail("商品卖完了");
            }
            //商品库存减-1
            redisUtils.decr(RedisKey.mallGoodCount + secKillGoodParams.getGoodId(), 1);
            //标记该用户已购买了该商品
            redisUtils.sSet(RedisKey.mallSecKillUser+secKillGoodParams.getGoodId(),
                    secKillGoodParams.getUserId());

        } catch (Exception e) {
            e.printStackTrace();
            throw new SystemException();
        } finally {
            lock.unlock();
        }

        MallOrder mallOrder = new MallOrder();
        BeanUtil.copyProperties(secKillGoodParams,mallOrder);
        //设置当前时间
        mallOrder.setCreateTime(LocalDateTime.now());
        mallOrder.setUserId(Long.valueOf(secKillGoodParams.getUserId()));
        //设置订单价格
        mallOrder.setTotal(secKillGoodParams.getGoodSecKillPrice().toString());

        //设置订单状态
        mallOrder.setStatus(0);

        mallOrderService.save(mallOrder);
        //插入中间表
        mallOrderMapper.insertOrder(mallOrder.getOrderId(), secKillGoodParams.getGoodId(), 1);
        //存入redis 设置过期时间
        redisUtils.set(RedisKey.redisOrderKey+secKillGoodParams.getUserId()+secKillGoodParams.getGoodId(),
                mallOrder.getOrderId());

        OrderParam orderParam = new OrderParam();

//
        orderParam.setOrderId(mallOrder.getOrderId());
        // 默认购买1件
        orderParam.setGoodId(new String[]{secKillGoodParams.getGoodId().toString()});
        orderParam.setGoodCount(new int[]{1});
        //投递消息队列
        rabbitTemplate.convertAndSend("orderExChange", "orderKey", orderParam);



        return Result.succ("抢购成功");


    }
}
